package wiki.xsx.jg.core;

import java.math.BigDecimal;
import java.util.*;

/**
 * SQLServer实现类
 */
public class SQLServerService extends AbstractService{

    public SQLServerService(Database database) {
        super(database);
    }

    @Override
    public String getDropTableSQL(String className) {
        StringBuilder sql = new StringBuilder();
        sql.append("IF EXISTS(SELECT 1 FROM sysobjects WHERE name='").append(className).append("') ")
            .append("DROP TABLE ").append(className);
        return sql.toString();
    }

    @Override
    public Map<String, Object> getCreateTableSQLMap(Entity entity) {
        Map<String, Object> SQLMap = new HashMap<>();
        Queue<String> commentQueue = new LinkedList<>();
        StringBuilder pk = new StringBuilder();
        StringBuilder comment = new StringBuilder();
        StringBuilder sql = new StringBuilder();
        sql.append("CREATE TABLE ").append(super.getDatabase().getName()).append(".dbo.").append(entity.getName()).append("(");
        for (Field field : entity.getColumnSet()){
            sql.append(field.getName()).append(" ");
            if (field.getType()!=null){
                sql.append(field.getType());
            }else{
                sql.append(getDataType(field.getJavaType()));
            }
            if (field.getIsNotNull()){
                sql.append(" NOT NULL ");
            }
            if (field.getDefaultValue()!=null){
                sql.append(" DEFAULT ").append(field.getDefaultValue());
            }
            sql.append(",");
            if (field.getIsPrimaryKey()){
                pk.append(field.getName()).append(",");
            }
            if (field.getComment()!=null){
                comment.append("EXEC sys.sp_addextendedproperty @name=N'MS_Description',")
                        .append("@value=N'").append(field.getComment()).append("',")
                        .append("@level0type=N'SCHEMA',@level0name=N'dbo',@level1type=N'TABLE',")
                        .append("@level1name=N'").append(entity.getName()).append("',")
                        .append("@level2type=N'COLUMN',")
                        .append("@level2name=N'").append(field.getName()).append("';");
            }
        }
        if (pk.length()>0){
            sql.append("PRIMARY KEY (").append(pk.substring(0, pk.length()-1)).append(")");
        }else{
            sql = sql.deleteCharAt(sql.length()-1);
        }
        sql.append(") ");
        if (entity.getComment()!=null){
            comment.append("EXEC sys.sp_addextendedproperty @name=N'MS_Description',")
                    .append("@value=N'").append(entity.getComment()).append("',")
                    .append("@level0type=N'SCHEMA',@level0name=N'dbo',@level1type=N'TABLE',")
                    .append("@level1name=N'").append(entity.getName()).append("';");
        }
        if (comment.length()>0){
            sql.append(comment);
        }
        SQLMap.put("createSQL", sql.toString());
        SQLMap.put("commentSQL", commentQueue);
        return SQLMap;
    }

    @Override
    public Class<?> getTypeClass(String dataTypeName, int length, int scale) {
        if (dataTypeName.matches("CHAR|NCHAR|VARCHAR|NVARCHAR|TEXT|NTEXT|UNIQUEIDENTIFIER|XML")){
            return String.class;
        }else if(dataTypeName.matches("INT")) {
            return Integer.class;
        }else if(dataTypeName.matches("SMALLINT|TINYINT")) {
            return Short.class;
        }else if(dataTypeName.matches("BIGINT")) {
            return Long.class;
        }else if(dataTypeName.matches("REAL")) {
            return Float.class;
        }else if(dataTypeName.matches("FLOAT")) {
            return Double.class;
        }else if(dataTypeName.matches("DECIMAL|NUMERIC|SMALLMONEY|MONEY")) {
            return BigDecimal.class;
        }else if(dataTypeName.matches("DATE|TIME|DATETIME|DATETIME2|SMALLDATETIME|DATETIMEOFFSET")) {
            return Date.class;
        }else if(dataTypeName.matches("TIMESTAMP|BINARY|IMAGE|VARBINARY")) {
            return byte[].class;
        }else if(dataTypeName.matches("BIT")) {
            return Boolean.class;
        }else{
            return Object.class;
        }
    }

    @Override
    public String getDataType(Class<?> type) {
        StringBuilder builder = new StringBuilder();
        switch (type.getSimpleName().toLowerCase()){
            case "string":
                builder.append("NVARCHAR(255)");
                break;
            case "integer":
                builder.append("INT");
                break;
            case "float":
                builder.append("REAL");
                break;
            case "double":
                builder.append("FLOAT");
                break;
            case "long":
                builder.append("BIGINT");
                break;
            case "short":
                builder.append("SMALLINT");
                break;
            case "bigdecimal":
                builder.append("DECIMAL");
                break;
            case "date":
                builder.append("DATETIME");
                break;
            case "time":
                builder.append("DATETIME");
                break;
            case "timestamp":
                builder.append("DATETIME");
                break;
            case "boolean":
                builder.append("BIT");
                break;
            case "byte[]":
                builder.append("VARBINARY");
                break;
            default:
                builder.append("NVARCHAR(255)");
        }
        return builder.toString();
    }
}
